package com.ys.service.storage.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ys.config.MenuId;
import com.ys.dto.AddDto;
import com.ys.entity.storage.*;
import com.ys.entity.flow.YspModel;
import com.ys.entity.sys.TsUserChange;
import com.ys.entity.sys.YsCol;
import com.ys.entity.sys.YsMenu;
import com.ys.entity.sys.YsProcInst;
import com.ys.enume.flow.FlowEnum;
import com.ys.enume.flow.YsProcInstEnum;
import com.ys.enume.storage.TccStockSourceEnum;
import com.ys.mapper.storage.*;
import com.ys.mapper.hr.HrMapper;
import com.ys.service.business.TcwAccountDetailedForCompanyService;
import com.ys.service.storage.TccStockControlService;
import com.ys.service.storage.TccStockOutboundService;
import com.ys.service.flow.YspTaskService;
import com.ys.service.sys.CommonApiService;
import com.ys.util.CheckUtil;
import com.ys.util.shiro.ShiroUtils;
import com.ys.vo.Flow;
import com.ys.vo.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 *
 */
@Service("tccStockOutboundService")
public class TccStockOutboundServiceImpl implements TccStockOutboundService {
	@Autowired
	private TccStockOutboundMapper tccStockOutboundMapper;

	@Autowired
	private TccStockOutboundItemMapper tccStockOutboundItemMapper;

	@Autowired
	private TccStockControlRunningMapper tccStockControlRunningMapper;

	@Autowired
	private StorageMapper storageMapper;

	@Autowired
	private YspTaskService yspTaskService;

	@Autowired
	private CheckUtil checkUtil;

	@Autowired
	private HrMapper hrMapper;

	@Autowired
	private TccStockControlService tccStockControlService;

	@Autowired
	private CommonApiService<TccStockOutbound> commonApiService;

	@Autowired
	private TccStockSourceMapper tccStockSourceMapper;
	/*
	 * 新增
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R add(String bid, String remark, String detailArr ) throws Exception {
		if (bid == null){
			return R.error("单号不允许为空!");
		}
		TccStockOutbound tccStockOutbound = new TccStockOutbound();
		tccStockOutbound.setBid(bid);
		tccStockOutbound.setRemark(remark);

		// 验证是否有详情数据
		JSONArray detailJA = JSON.parseArray(detailArr);
		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		}

		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			if (detailJO.getInteger("num") == null){
				return R.error("出库数量不能为空!");
			}else if (detailJO.getInteger("num") == 0){
				return R.error("出库数量不能0!");
			}
		}

		String loginUserId = ShiroUtils.getUserId();
		TsUserChange tsUserChange = new TsUserChange().setUserId(loginUserId).setStatus(1).queryFirst();

		tccStockOutbound.setStatus(1);
		tccStockOutbound.setCreateChangeld(tsUserChange.getId());
		tccStockOutbound.setEffectStock(FlowEnum.EffectStock.NOT_EFFECT.value);
		tccStockOutboundMapper.insert(tccStockOutbound);


		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			TccStockOutboundItem tccStockOutboundItem = JSON.parseObject(JSON.toJSONString(detailJO), TccStockOutboundItem.class);
			TccStockControl tccStockControl = JSON.parseObject(JSON.toJSONString(detailJO), TccStockControl.class).setProductCode(tccStockOutboundItem.getProductCode());
			tccStockOutboundItem.setPbid(bid);
			tccStockOutboundItem.setControlId(Long.parseLong(detailJO.get("controlId").toString()));
			tccStockOutbound.setStatus(1);
			if(tccStockOutboundItem.getNum()<=tccStockControl.getProductNum()) {
				tccStockOutboundItemMapper.insert(tccStockOutboundItem);
			}else {
				return  R.error("出库数量不能超过库存可用数量！");
			}
		}
		YsMenu ysMenu = new YsMenu().setId(MenuId.TCC_StockOutbound).queryFirst();
		if (ysMenu.getFlowModelId().longValue() != 0L) {
			YspModel yspModel = new YspModel().setId(ysMenu.getFlowModelId()).queryFirst();
			String codeModel = yspModel.getCode();
			String createUserId = ShiroUtils.getUserId();
			yspTaskService.init(codeModel, bid, createUserId);
		}
		return R.ok(AddDto.gotoEdit("/web/storage/tccStockOutbound/toEdit?bid=" + bid));
	}

	/**
	 * 修改
	 * @throws Exception
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R edit(String bid, String remark, String detailArr) throws Exception {
		if (bid == null){
			return R.error("单号不允许为空!");
		}
		TccStockOutbound tccStockOutbound = new TccStockOutbound().setBid(bid).queryFirst();
		if (tccStockOutbound == null){
			return R.error("货位转移单不存在!");
		}
		tccStockOutbound.setRemark(remark);

		// 验证是否有详情数据
		JSONArray detailJA = JSON.parseArray(detailArr);
		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		}

		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			if (detailJO.getInteger("num") == null){
				return R.error("出库数量不能为空!");
			}else if (detailJO.getInteger("num") == 0){
				return R.error("出库数量不能0!");
			}
		}

		tccStockOutboundMapper.update(tccStockOutbound);

		hrMapper.deleteTccStockOutboundItemByBid(bid);

		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			TccStockOutboundItem tccStockOutboundItem = JSON.parseObject(JSON.toJSONString(detailJO), TccStockOutboundItem.class);
			TccStockControl tccStockControl = JSON.parseObject(JSON.toJSONString(detailJO), TccStockControl.class).setProductCode(tccStockOutboundItem.getProductCode());
			tccStockOutboundItem.setPbid(bid);
			tccStockOutbound.setStatus(1);
			tccStockOutboundItem.setControlId(tccStockControl.getId());
			if(tccStockOutboundItem.getNum()<=tccStockControl.getProductNum()) {
				tccStockOutboundItemMapper.insert(tccStockOutboundItem);
			}else {
				return  R.error("出库数量不能超过库存可用数量！");
			}
		}

		return R.ok(AddDto.gotoEdit("/web/storage/tccStockOutbound/toEdit?bid=" + bid));
	}



	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R deleteTrue(Long id) throws Exception {
		if (id == null) {
			return R.error("ID不能为空");
		}
		TccStockOutbound entity = new TccStockOutbound().setId(id).queryFirst();
		if (entity.getEffectStock() == FlowEnum.EffectStock.EFFECTED.value) {
			return R.error("已生效数据无法删除");
		}
		// 验证是否制单人
		String loginUserId = ShiroUtils.getUserId();
		TsUserChange tsUserChange = new TsUserChange().setId(entity.getCreateChangeld()).queryFirst();

		if (!tsUserChange.getUserId().equals(loginUserId)) {
			return R.error("非制单人，无法删除");
		}

		// 删除主数据
		tccStockOutboundMapper.deleteTrue(id);

		// 删除子数据
		List<TccStockOutboundItem> listDetail = new TccStockOutboundItem().setPbid(entity.getBid()).queryList();
		for(TccStockOutboundItem detail : listDetail) {
			tccStockOutboundItemMapper.deleteTrue(detail.getId());
		}

		yspTaskService.flowDelete(entity.getBid(), loginUserId);
		return R.ok();
	}

	/**
	 * 流转
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R flowPass(Long id, String loginUserId) throws Exception {
		TccStockOutbound entity = new TccStockOutbound().setId(id).queryFirst();
		if (entity == null) {
			return R.error("库存出库单不存在!");
		}
		try {
			String bid = entity.getBid();
			YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();
			Flow f = yspTaskService.flowPass(bid, loginUserId);

			if (f.getCode() == Flow.Code.FAILED.value) {
				return R.error(f.getMsg());
			} else {
				// 若是制单流转，冻结库存
				if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
					List<TccStockOutboundItem> itemList = new TccStockOutboundItem().setPbid(bid).queryList();
					if(itemList == null || itemList.size()<=0){
						return R.error("该单据列表不存在,请核实后再操作!");
					}
					//冻结
					for(TccStockOutboundItem item:itemList){
						tccStockControlService.frozen(
								item.getControlId(),
								item.getNum(),
								TccStockSourceEnum.Source.TCC_StockOutbound.value,
								entity.getBid(),
								item.getId()
						);
					}
				}
				if (f.getState() == Flow.State.FINISH.value) {
					R r = flowFinish(entity);
					if (r.getCode() == 1) {
						return R.error(r.getMsg());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}
		return R.ok();
	}

	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R flowRefuse(Long id, String reason, String loginUserId) throws Exception {
		TccStockOutbound entity = new TccStockOutbound().setId(id).queryFirst();
		if (entity == null) {
			return R.error("库存出库单不存在!");
		}
		String bid = entity.getBid();
		R r = yspTaskService.flowRefuse(bid, reason, ShiroUtils.getUserId());
		YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();

		if (r.getCode() == R.Code.SUCCESS.value) {
			// 若退回到制单状态，则解冻库存
			if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
				List<TccStockOutboundItem> itemList = new TccStockOutboundItem().setPbid(bid).queryList();
				if(itemList == null || itemList.size()<=0){
					throw new IllegalArgumentException("该单据列表不存在,请核实后再操作!");
				}
				//解冻
				for(TccStockOutboundItem item:itemList){
					tccStockControlService.thaw(
							item.getControlId(),
							item.getNum(),
							TccStockSourceEnum.Source.TCC_StockOutbound.value,
							entity.getBid(),
							item.getId()
					);
				}
			}
		}
		return r;
	}

	//流转驳回
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R flowInit(Long id, String reason,String loginUserId) throws Exception{
		TccStockOutbound entity = new TccStockOutbound().setId(id).queryFirst();
		if (entity == null) {
			return R.error("库存出库单不存在!");
		}
		String bid = entity.getBid();
		R r = yspTaskService.flowInit(bid, reason, ShiroUtils.getUserId());
		YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();
		if (r.getCode() == R.Code.SUCCESS.value) {
			// 若退回到制单状态，则解冻库存
			if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
				List<TccStockOutboundItem> itemList = new TccStockOutboundItem().setPbid(bid).queryList();
				if(itemList == null || itemList.size()<=0){
					throw new IllegalArgumentException("该单据列表不存在,请核实后再操作!");
				}
				//解冻
				for(TccStockOutboundItem item:itemList){
					tccStockControlService.thaw(
							item.getControlId(),
							item.getNum(),
							TccStockSourceEnum.Source.TCC_StockOutbound.value,
							entity.getBid(),
							item.getId()
					);
				}
			}
		}
		return r;
	}

	/**
	 * 流转结束
	 */
	public R flowFinish(TccStockOutbound entity) throws Exception {
		try {
			YsProcInst ysProcInst = new YsProcInst().setBid(entity.getBid()).queryFirst();
			if (ysProcInst.getStateFlow() != YsProcInstEnum.StateFlow.FINISH.value) {
				return R.error("流程状态有误");
			}
			Date theDate = new Date();
			entity.setEffectStock(FlowEnum.EffectStock.EFFECTED.value);
			entity.setUpdateTime(theDate);

			List<TccStockOutboundItem> tccStockOutboundItems = new TccStockOutboundItem().setPbid(entity.getBid()).queryList();
			for (TccStockOutboundItem tccStockOutboundItem : tccStockOutboundItems){
				//解冻
				tccStockControlService.thaw(
						tccStockOutboundItem.getControlId(),
						tccStockOutboundItem.getNum(),//数量
						TccStockSourceEnum.Source.TCC_StockOutbound.value,
						entity.getBid(),
						entity.getId()
				);
				//出库
				String remark = "库存出库单单号：" + entity.getBid();
				Integer numOut = tccStockOutboundItem.getNum();
				Integer sourceTypeOut = TccStockSourceEnum.Source.TCC_StockOutbound.value;
				tccStockControlService.outWithRunning(tccStockOutboundItem.getControlId(), remark + ",出库", numOut, entity.getBid(),sourceTypeOut,entity.getId());

				Long stockControlId = tccStockOutboundItem.getControlId();
				TccStockControl tccStockControl = new TccStockControl().setId(stockControlId).queryFirst();

				tccStockOutboundItemMapper.update(tccStockOutboundItem);
			}
			tccStockOutboundMapper.update(entity);
		}catch (Exception e){
			throw new RuntimeException(e.getMessage());
		}
		return R.ok();
	}
	//获取列表数据
	@Override
	@Transactional
	public Map<String,Object> getExtraParam( String bid) throws Exception{
		Map<String,Object> entity = new TccStockOutbound()

				.addLeftJoin("YS_ProcInst P ON P.Bid = A.Bid ")
				.addLeftJoin("TS_UserChange U ON U.Id = A.CreateChangeld ")
				.addField("U.UserId + '/' + U.UserName AS _ys_createUserName")//制单人
				.addField("CASE WHEN P.UpdateTime IS NULL AND A.EffectStock = 1 THEN FORMAT(A.UpdateTime, 'yyyy-MM-dd HH:mm:ss') ELSE FORMAT(P.UpdateTime, 'yyyy-MM-dd HH:mm:ss') END auditingTime")//审核时间
				.addLeftJoin("TCC_StockOutboundItem B ON B.Pbid=A.Bid")
				.addLeftJoin("TB_CompanyInfo D ON D.Vid=B.CompanyVid")
				.addLeftJoin("TCC_StockControl C ON C.ProductCode=B.ProductCode")
				.addField("C.Id controlId,C.ProductName productName,C.ProductCode productCode,C.ProductCode codeMerge,C.ProductNum productNum," +
						"C.ProductNumAll productNumAll,C.Gdepot gdepot,C.Vkq vkq,C.Vhw vhw,C.Sdays kcdays," +
						"C.Drksj drksj,C.Vgsbm vgsbm,C.Vgsjc vgsjc,D.Vname companyVname,B.Num num")
				.setBid(bid)
				.queryFirstMap();

		return entity;
	}


	//获取子列表数据
	@Override
	@Transactional
	public List<Map<String, Object>> getItemList( String bid) throws Exception{
		List<Map<String, Object>> itemList = new TccStockOutboundItem()

				.addLeftJoin("TCC_StockOutbound B ON A.Pbid=B.Bid")
				.addLeftJoin("TB_CompanyInfo D ON D.Vid=A.CompanyVid")
				.addLeftJoin("TCC_StockControl C ON C.Id=A.ControlId")
				.addField("C.Id controlId,C.ProductName productName,C.ProductCode productCode,C.ProductCode subCodeMerge,C.ProductNum productNum," +
						"C.ProductNumAll productNumAll,C.Gdepot gdepot,C.Vkq vkq,C.Vhw vhw,C.Sdays kcdays," +
						"C.Drksj drksj,C.Vgsbm vgsbm,C.Vgsjc vgsjc,D.Vname vname,A.Num num,C.RkBid rkBid")

				.setPbid(bid)
				.queryMap();
		return itemList;
	}
	@Override
	@Transactional
	public R toDelByItem(Long id) throws Exception {

		TccStockOutboundItem tccStockOutboundItem = new TccStockOutboundItem();
		tccStockOutboundItem.setId(id);
		tccStockOutboundItem.setStatus(0);
		tccStockOutboundItemMapper.update(tccStockOutboundItem);
		return R.ok();
	}
}